package com.lj.infoisland.service.Impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.lj.infoisland.common.convention.errorcode.BaseErrorCode;
import com.lj.infoisland.common.convention.result.Result;
import com.lj.infoisland.common.convention.result.Results;
import com.lj.infoisland.domain.dto.AdminUserInfo;
import com.lj.infoisland.domain.dto.LoginDTO;
import com.lj.infoisland.domain.dto.RegisterDTO;
import com.lj.infoisland.domain.dto.UserInitInfoDTO;
import com.lj.infoisland.domain.po.News;
import com.lj.infoisland.domain.po.Users;
import com.lj.infoisland.domain.vo.LoginVO;
import com.lj.infoisland.domain.vo.UserInfoVO;
import com.lj.infoisland.mapper.UsersMapper;
import com.lj.infoisland.service.NewsService;
import com.lj.infoisland.service.UsersService;
import com.lj.infoisland.util.AssertUtil;
import com.lj.infoisland.util.UserContext;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

import static com.lj.infoisland.util.JwtUtil.generateToken;


/*
 * @description 用户服务类Impl
 * @author 龙洁
 * @create 2024-10-21 下午10:24
 */
@Service
public class UserServiceImpl extends ServiceImpl<UsersMapper, Users> implements UsersService {

    // 修改名字前缀
    private static final String USER_NAME_ALTER_PREFIX = "user_name_alter:";
    // 手机号验证码绑定前缀
    private static final String PHONE_CODE_ERROR = "phone_verify:";
    @Value("${minio.FILE_PREFIX}")
    private String FILE_PREFIX;
    @Resource
    private StringRedisTemplate stringRedisTemplate;
    @Resource
    private NewsService newsService;

    @Override
    public Result<?> login(LoginDTO loginDto) {
        // 检验用户信息
        AssertUtil.isUserNameNull(loginDto.getUsername());
        AssertUtil.validatePassword(loginDto.getPassword());
        LambdaQueryWrapper<Users> wrapper = Wrappers.lambdaQuery(Users.class)
                .eq(Users::getUsername, loginDto.getUsername());
        Users users = baseMapper.selectOne(wrapper);

        // 判断用户是否为空
        if (users == null) {
            return Results.failure(BaseErrorCode.USER_INFO_NULL);
        } else {
            if (users.getStatus() == 0){
                return Results.failure(BaseErrorCode.USER_STATUS_ERROR);
            }
            // 判断密码是否正确
            if (loginDto.getPassword().equals(users.getPassword())) {
                String token = generateToken(users.getUserUniqueId());
                LoginVO loginVO = new LoginVO();
                loginVO.setToken(token);
                loginVO.setIsInit(users.getIsInit());
                // 返回并且携带token
                return Results.success(loginVO);
            } else {
                return Results.failure(BaseErrorCode.USER_PASSWORD_ERROR);
            }
        }
    }

    @Override
    public Result<?> register(RegisterDTO registerDTO) {
        // 校验注册信息
        AssertUtil.isUserNameNull(registerDTO.getUsername());
        AssertUtil.validatePassword2(registerDTO.getPassword(), registerDTO.getConfirmPassword());
        // 判断用户名是否重复
        LambdaQueryWrapper<Users> wrapper = Wrappers.lambdaQuery(Users.class)
                .eq(Users::getUsername, registerDTO.getUsername());
        Users users = baseMapper.selectOne(wrapper);
        // 判断用户名是否重复
        if (users != null) {
            return Results.failure(BaseErrorCode.USER_NAME_EXIST_ERROR);
        } else {
            // 插入用户信息
            Users user = new Users();
            user.setUsername(registerDTO.getUsername());
            user.setPassword(registerDTO.getPassword());
            user.setRole("user");
            baseMapper.insert(user);
        }
        return Results.success();
    }

    @Override
    public Result<UserInfoVO> getUserInfo(String userUniqueId) {
        LambdaQueryWrapper<Users> eq = Wrappers.lambdaQuery(Users.class)
                .eq(Users::getUserUniqueId, userUniqueId);
        Users users = baseMapper.selectOne(eq);
        UserInfoVO bean = BeanUtil.toBean(users, UserInfoVO.class);
        bean.setAvatarUrl(FILE_PREFIX + users.getAvatarUrl());
        bean.setPublishNum(newsService.count(Wrappers.lambdaQuery(News.class).eq(News::getUserUniqueId, userUniqueId)));
        return Results.success(bean);
    }


    @Override
    public Users getUserByUserUniqueId(String userUniqueId) {
        LambdaQueryWrapper<Users> eq = Wrappers.lambdaQuery(Users.class)
                .eq(Users::getUserUniqueId, userUniqueId);
        Users users = baseMapper.selectOne(eq);
        return users;
    }

    @Override
    public Result<Void> alterUserInfo(UserInfoVO userInfoVO) {
        LambdaQueryWrapper<Users> eq = Wrappers.lambdaQuery(Users.class)
                .eq(Users::getUserUniqueId, userInfoVO.getUserUniqueId());
        Users users = baseMapper.selectOne(eq);
        // 如果用户名不相等，需要判断是否在三十天内修改过名字
        if (!Objects.equals(users.getUsername(), userInfoVO.getUsername())) {
            String s = stringRedisTemplate.opsForValue().get(USER_NAME_ALTER_PREFIX + userInfoVO.getUserUniqueId());
            if (!StrUtil.isEmpty(s)) {
                return Results.failure(BaseErrorCode.USER_NAME_ALTER_ERROR);
            } else {
                // 三十天的缓存过期时间
                stringRedisTemplate.opsForValue().set(USER_NAME_ALTER_PREFIX + userInfoVO.getUserUniqueId(), "1", 30L, TimeUnit.DAYS);
            }
        }
        LambdaUpdateWrapper<Users> set = Wrappers.lambdaUpdate(Users.class)
                .eq(Users::getUserUniqueId, userInfoVO.getUserUniqueId())
                .set(Users::getUsername, userInfoVO.getUsername())
                .set(Users::getEmail, userInfoVO.getEmail())
                .set(Users::getAddress, userInfoVO.getAddress())
                .set(Users::getDescription, userInfoVO.getDescription());
        update(set);
        return Results.success();
    }

    @Override
    public Result<Void> alterPhoneNumber(String phoneNumber, String code) {
        String s = stringRedisTemplate.opsForValue().get(PHONE_CODE_ERROR + phoneNumber);
        UserInfoVO user = UserContext.getUser();
        if (s == null || !s.equals(code)) {
            return Results.failure(BaseErrorCode.CODE_ERROR);
        } else {
            LambdaUpdateWrapper<Users> set = Wrappers.lambdaUpdate(Users.class)
                    .eq(Users::getUserUniqueId, user.getUserUniqueId())
                    .set(Users::getPhoneNumber, phoneNumber);
            update(set);
            return Results.success();
        }
    }

    @Override
    public Result<?> setVerificationCode(String phoneNumber, String code) {
        String s = stringRedisTemplate.opsForValue().get(PHONE_CODE_ERROR + phoneNumber);
        if (s != null) {
            return Results.failure(BaseErrorCode.PHONE_CODE_ERROR);
        } else {
            stringRedisTemplate.opsForValue().set(PHONE_CODE_ERROR + phoneNumber, code, 1L, TimeUnit.MINUTES);
            return Results.success(code);
        }
    }

    @Override
    public String getUserNameById(String userUniqueId) {
        LambdaQueryWrapper<Users> eq = Wrappers.lambdaQuery(Users.class)
                .eq(Users::getUserUniqueId, userUniqueId);
        return baseMapper.selectOne(eq).getUsername();
    }

    @Override
    @Transactional()
    public Result<?> initUserInfo(UserInitInfoDTO userInitInfoDTO) {
        UserInfoVO user = UserContext.getUser();
        if (user.getIsInit() == 0) {
            LambdaUpdateWrapper<Users> wrapper = Wrappers.lambdaUpdate(Users.class)
                    .eq(Users::getUserUniqueId, user.getUserUniqueId())
                    .set(Users::getSex, Integer.parseInt(userInitInfoDTO.getSex()))
                    .set(Users::getBirthday, userInitInfoDTO.getBirthday())
                    .set(Users::getInterests, userInitInfoDTO.getInterests())
                    .set(Users::getAvatarUrl, userInitInfoDTO.getSex().equals("1") ? "man.png" : "woman.png")
                    .set(Users::getIsInit, 1);
            update(wrapper);
        } else {
            return Results.failure(BaseErrorCode.USER_INIT_ERROR);
        }
        return Results.success();
    }

    @Override
    public Integer getNewUsersCount() {
        // 查询近7天的新增用户数量count
        return baseMapper.getNewUsersCount();
    }

    @Override
    public Integer getWeekUserCount(int i) {
        return baseMapper.getWeekUserCount(i);
    }

    @Override
    public List<Users> getUserList(Integer pageNum, Integer pageSize,String username,String role) {
        LambdaQueryWrapper<Users> wrapper = new LambdaQueryWrapper<>();
        wrapper.orderByDesc(Users::getCreatedAt);
        if (StrUtil.isNotEmpty(username)) {
            wrapper.like(Users::getUsername, username);
        }
        if (StrUtil.isNotEmpty(role)) {
            wrapper.eq(Users::getRole, role);
        }
        Page<Users> objectPage = new Page<>(pageNum, pageSize);
        IPage<Users> usersIPage = baseMapper.selectPage(objectPage, wrapper);
        List<Users> list = usersIPage.getRecords().stream().map(user -> {
            user.setAvatarUrl(FILE_PREFIX + user.getAvatarUrl());
            return user;
        }).toList();
        return list;
    }

    @Override
    public void addAdminUser(AdminUserInfo adminUserInfo) {
        Users users = new Users();
        BeanUtil.copyProperties(adminUserInfo, users);
        users.setAvatarUrl("man.png");
        users.setRole("admin");
        baseMapper.insert(users);
    }

    @Override
    public void updateUserStatus(String userUniqueId, Integer status) {
        // 用户状态: 0: 禁用, 1: 启用
        Users user = getUserByUserUniqueId(userUniqueId);
        user.setStatus(status);
        baseMapper.updateById(user);
    }

    @Override
    public Long getUserTotal() {
        return count();
    }
}
